<script lang="ts" setup>
import type { PolicyRule } from "@halo-dev/api-client";
import { Toast } from "@halo-dev/components";

import SubmitButton from "@/components/button/SubmitButton.vue";
import { useRoleForm, useRoleTemplateSelection } from "@/composables/use-role";
import { rbacAnnotations } from "@/constants/annotations";
import { pluginLabels, roleLabels } from "@/constants/labels";
import { setFocus } from "@/formkit/utils/focus";
import {
  useCategorySelection,
  usePostCategory,
} from "@console/modules/contents/posts/categories/composables/use-post-category";
import type { CategoryTree } from "@console/modules/contents/posts/categories/utils";
import type { Role } from "@halo-dev/api-client";
import { coreApiClient } from "@halo-dev/api-client";
import { VButton, VModal, VSpace } from "@halo-dev/components";
import { useQuery } from "@tanstack/vue-query";
import { cloneDeep } from "lodash-es";
import { onMounted, ref, watch } from "vue";
import { useI18n } from "vue-i18n";
const { categories, categoriesTree } = usePostCategory();
const { t } = useI18n();

const props = withDefaults(
  defineProps<{
    role?: Role;
  }>(),
  {
    role: undefined,
  }
);

const emit = defineEmits<{
  (event: "close"): void;
}>();

const modal = ref<InstanceType<typeof VModal> | null>(null);

const { data: roleTemplates } = useQuery({
  queryKey: ["role-templates"],
  queryFn: async () => {
    const { data } = await coreApiClient.role.listRole({
      page: 0,
      size: 0,
      labelSelector: [`${roleLabels.TEMPLATE}=true`, "!halo.run/hidden"],
    });
    return data.items;
  },
});

const { selectedCategories, hadPostMange } = useCategorySelection(categories);

const { roleTemplateGroups, handleRoleTemplateSelect, selectedRoleTemplates } =
  useRoleTemplateSelection(roleTemplates);

const { formState, isSubmitting, handleCreateOrUpdate } = useRoleForm();

watch(
  () => selectedRoleTemplates.value,
  (newValue) => {
    if (formState.value.metadata.annotations) {
      formState.value.metadata.annotations[rbacAnnotations.DEPENDENCIES] =
        JSON.stringify(Array.from(newValue));
    }
  }
);

const setCategoryPermission = (
  PermissionList: Array<string>,
  categoriesTree: CategoryTree[]
): Array<string> => {
  categoriesTree.forEach((item: CategoryTree) => {
    if (
      PermissionList.some(
        (permision: string) => permision === item.metadata.name
      ) &&
      item.spec.available
    ) {
      PermissionList.push(
        ...(item.spec.children.length
          ? item.spec.children.map((child: CategoryTree) => child.metadata.name)
          : [])
      );
      PermissionList = Array.from(
        new Set([
          ...PermissionList,
          ...setCategoryPermission(PermissionList, item.spec.children),
        ])
      );
    }
  });
  return PermissionList;
};

watch(
  () => selectedCategories.value,
  (newValue) => {
    if (formState.value.rules) {
      const categoryIndex =
        formState.value.rules.length &&
        formState.value.rules.findIndex(
          (rule: PolicyRule) =>
            rule?.resources && rule?.resources[0] === "categories"
        );
      formState.value.rules[categoryIndex] = {
        apiGroups: ["content.halo.run"],
        nonResourceURLs: [],
        // resourceNames: Array.from(newValue),
        resourceNames: setCategoryPermission(
          Array.from(newValue),
          categoriesTree.value
        ),
        resources: ["categories"],
      };
    }
  }
);

onMounted(() => {
  setFocus("displayNameInput");

  if (props.role) {
    formState.value = cloneDeep(props.role);
    const dependencies =
      props.role.metadata.annotations?.[rbacAnnotations.DEPENDENCIES];
    if (dependencies) {
      selectedRoleTemplates.value = new Set(JSON.parse(dependencies));
    }
    if (props.role.rules.length) {
      const categoryIndex = props.role.rules.findIndex(
        (rule: PolicyRule) =>
          rule?.resources && rule?.resources[0] === "categories"
      );
      selectedCategories.value =
        props.role.rules[categoryIndex].resourceNames || [];
    }
  }
});

const editingModalTitle = props.role
  ? t("core.role.editing_modal.titles.update")
  : t("core.role.editing_modal.titles.create");

const handleCreateOrUpdateRole = async () => {
  try {
    if (
      hadPostMange(selectedRoleTemplates.value) &&
      formState.value.rules.length &&
      formState.value.rules.some(
        (rule) =>
          rule.resources &&
          rule.resources.some((rsc) => rsc === "categories" || rsc === "*")
      )
    ) {
      await handleCreateOrUpdate();
      modal.value?.close();
    } else {
      Toast.warning("请绑定至少一个分类权限");
    }
  } catch (e) {
    console.error(e);
  }
};
</script>
<template>
  <VModal
    ref="modal"
    :title="editingModalTitle"
    :width="700"
    @close="emit('close')"
  >
    <div>
      <div class="md:grid md:grid-cols-4 md:gap-6">
        <div class="md:col-span-1">
          <div class="sticky top-0">
            <span class="text-base font-medium text-gray-900">
              {{ $t("core.role.editing_modal.groups.general") }}
            </span>
          </div>
        </div>
        <div class="mt-5 divide-y divide-gray-100 md:col-span-3 md:mt-0">
          <FormKit
            v-if="formState.metadata.annotations"
            id="role-form"
            name="role-form"
            :actions="false"
            type="form"
            :config="{ validationVisibility: 'submit' }"
            @submit="handleCreateOrUpdateRole"
          >
            <FormKit
              id="displayNameInput"
              v-model="
                formState.metadata.annotations[rbacAnnotations.DISPLAY_NAME]
              "
              :label="$t('core.role.editing_modal.fields.display_name')"
              type="text"
              validation="required|length:0,50"
            ></FormKit>
            <FormKit
              v-model="
                formState.metadata.annotations[
                  rbacAnnotations.DISALLOW_ACCESS_CONSOLE
                ]
              "
              on-value="true"
              off-value="false"
              type="checkbox"
              :label="
                $t(
                  'core.role.editing_modal.fields.disallow_access_console.label'
                )
              "
              :help="
                $t(
                  'core.role.editing_modal.fields.disallow_access_console.help'
                )
              "
            ></FormKit>
          </FormKit>
        </div>
      </div>
      <div class="py-5">
        <div class="border-t border-gray-200"></div>
      </div>
      <div class="md:grid md:grid-cols-4 md:gap-6">
        <div class="md:col-span-1">
          <div class="sticky top-0">
            <span class="text-base font-medium text-gray-900">
              {{ $t("core.role.editing_modal.groups.permissions") }}
            </span>
          </div>
        </div>
        <div class="mt-5 divide-y divide-gray-100 md:col-span-3 md:mt-0">
          <dl class="divide-y divide-gray-100">
            <template
              v-for="(group, groupIndex) in roleTemplateGroups"
              :key="groupIndex"
            >
              <div class="flex flex-col gap-3 bg-white py-5 first:pt-0">
                <dt class="text-sm font-medium text-gray-900">
                  <div>
                    {{
                      $t(`core.rbac.${group.module}`, group.module as string)
                    }}
                  </div>
                  <div
                    v-if="
                      group.roles.length &&
                      group.roles[0].metadata.labels?.[pluginLabels.NAME]
                    "
                    class="mt-3 text-xs text-gray-500"
                  >
                    <i18n-t
                      keypath="core.role.common.text.provided_by_plugin"
                      tag="div"
                    >
                      <template #plugin>
                        <RouterLink
                          :to="{
                            name: 'PluginDetail',
                            params: {
                              name: group.roles[0].metadata.labels?.[
                                pluginLabels.NAME
                              ],
                            },
                          }"
                          class="hover:text-blue-600"
                        >
                          {{
                            group.roles[0].metadata.labels?.[pluginLabels.NAME]
                          }}
                        </RouterLink>
                      </template>
                    </i18n-t>
                  </div>
                </dt>
                <dd class="text-sm text-gray-900">
                  <ul class="space-y-2">
                    <li
                      v-for="(roleTemplate, index) in group.roles"
                      :key="index"
                    >
                      <label
                        class="inline-flex w-full cursor-pointer flex-row items-center gap-4 rounded-base border p-5 hover:border-primary"
                      >
                        <input
                          v-model="selectedRoleTemplates"
                          :value="roleTemplate.metadata.name"
                          type="checkbox"
                          @change="handleRoleTemplateSelect"
                        />
                        <div class="flex flex-1 flex-col gap-y-3">
                          <span class="font-medium text-gray-900">
                            {{
                              $t(
                                `core.rbac.${
                                  roleTemplate.metadata.annotations?.[
                                    rbacAnnotations.DISPLAY_NAME
                                  ]
                                }`,
                                roleTemplate.metadata.annotations?.[
                                  rbacAnnotations.DISPLAY_NAME
                                ] as string
                              )
                            }}
                          </span>
                          <span
                            v-if="
                              roleTemplate.metadata.annotations?.[
                                rbacAnnotations.DEPENDENCIES
                              ]
                            "
                            class="text-xs text-gray-400"
                          >
                            {{
                              $t("core.role.common.text.dependent_on", {
                                roles: JSON.parse(
                                  roleTemplate.metadata.annotations?.[
                                    rbacAnnotations.DEPENDENCIES
                                  ]
                                )
                                  .map((item: string) =>
                                    $t(`core.rbac.${item}`, item as string)
                                  )
                                  .join("，"),
                              })
                            }}
                          </span>
                        </div>
                      </label>
                    </li>
                  </ul>
                </dd>
              </div>
              <div
                v-if="
                  group.module === 'Posts Management' &&
                  hadPostMange(selectedRoleTemplates)
                "
                class="flex flex-col gap-3 bg-white py-5 first:pt-0"
              >
                <dt class="text-sm font-medium text-gray-900">
                  <div>
                    {{ $t(`core.rbac.${"Categories Management"}`) }}
                  </div>
                </dt>
                <dd class="text-sm text-gray-900">
                  <FormKit
                    v-model="selectedCategories"
                    type="categorySelect"
                    multiple="true"
                    create="false"
                  ></FormKit>
                </dd>
              </div>
            </template>
          </dl>
        </div>
      </div>
    </div>
    <template #footer>
      <VSpace>
        <SubmitButton
          :loading="isSubmitting"
          type="secondary"
          :text="$t('core.common.buttons.submit')"
          @submit="$formkit.submit('role-form')"
        >
        </SubmitButton>
        <VButton @click="modal?.close()">
          {{ $t("core.common.buttons.cancel_and_shortcut") }}
        </VButton>
      </VSpace>
    </template>
  </VModal>
</template>
